package com.moliku.insurance.process.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.moliku.insurance.common.constant.CompanyEnum;
import com.moliku.insurance.common.constant.InsureStatusEnum;
import com.moliku.insurance.common.constant.OrderEnum;
import com.moliku.insurance.common.constant.PolicyConfigKeyEnum;
import com.moliku.insurance.common.response.CommonInsureResult;
import com.moliku.insurance.common.util.MD5Utils;
import com.moliku.insurance.model.dto.CancelInsureDTO;
import com.moliku.insurance.model.dto.DownloadInsureDTO;
import com.moliku.insurance.model.dto.insure.InsureDTO;
import com.moliku.insurance.model.dto.insure.InsuredInfoDTO;
import com.moliku.insurance.model.entity.Order;
import com.moliku.insurance.model.entity.OrderDetail;
import com.moliku.insurance.model.entity.generali.Data;
import com.moliku.insurance.model.entity.generali.GeneraliEntity;
import com.moliku.insurance.process.mapper.BaseOrderMapper;
import com.moliku.insurance.process.service.ConfigService;
import com.moliku.insurance.process.strategy.PolicyStrategy;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 中意人寿
 *
 * @author Mr.Liu
 * @since 2021/2/25
 */
@Slf4j
@Service("GeneraliService")
@AllArgsConstructor
public class GeneraliServiceImpl implements PolicyStrategy {

    private final ConfigService configService;

    private final RestTemplate restTemplate;

    private final BaseOrderMapper baseOrderMapper;
    /**
     * 询价方法名
     */
    private static final String QUOTE = "Quote";
    /**
     * 投保方法名
     */
    private static final String NSELL = "NSell";
    /**
     * 退保方法名
     */
    private static final String CANCELLATION = "Cancellation";
    /**
     * 下载方法名
     */
    private static final String GENERATEDOC = "GenerateDoc";


    /**
     * 默认性别女为0
     */
    private final String BASE_WOMAN = "0";
    /**
     * 中意返回成功编码
     */
    private final int RESPONSE_SUCCESS_CODE = 200;
    /**
     * 中意返回json串中的响应码
     */
    private final String RETURN_CODE = "returnCode";
    /**
     * 中意返回json串中的相应信息
     */
    private final String RETURN_MSG = "returnMsg";
    /**
     * 中意返回的成功信息
     */
    private final String OK = "OK";

    @Override
    public CommonInsureResult submitPolicy(InsureDTO request) {
        Order order = baseOrderMapper.selectById(request.getLocalOrderId());
        if (null == order) {
            log.info("中意投保失败,未查询到该订单:{}", request.getLocalOrderId());
            return CommonInsureResult.submitPolicyFail(InsureStatusEnum.INSURE_FAIL_5102);
        }
        //密钥等信息
        String submitUrl = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
        String agencyUserId = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.AGENCY_USERID);
        String privateKey = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.PRIVATE_KEY);

        //实体  询价开始
        GeneraliEntity generaliEntity = new GeneraliEntity();
        generaliEntity.setTransNo(request.getOrder().getSerialNumber());
        //开发者标识
        generaliEntity.setAgencyUserId(agencyUserId);
        //订单创建时间
        generaliEntity.setCreateTime(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss"));
        //中意业务json字符串
        Data datas = new Data();
        //被保人集合
        List<Data.Insured> insureds = new ArrayList<>();
        //受益人集合
        List<Data.Beneficiary> beneficiaryList = new ArrayList<>();
        //中意基本信息
        Data.PolicyInfo policyInfo = new Data.PolicyInfo();
        policyInfo.setPlanCode(request.getOrder().getProductCode());
        policyInfo.setExtendedPlanCode("");
        policyInfo.setTransactionEffDate(request.getOrder().getStartTime());
        policyInfo.setTransactionExpDate(request.getOrder().getEndTime());
        //TODO
        policyInfo.setCopiesCout(1);
        datas.setPolicyInfo(policyInfo);
        //投保人
        Data.Holder holder = new Data.Holder();
        holder.setName(request.getPolicyHolder().getcName());
        holder.setSex(BASE_WOMAN.equals(request.getPolicyHolder().getSex()) ? "2" : "1");
        holder.setBirthday(request.getPolicyHolder().getBirthDay());
        holder.setIdType(GeneraliEntity.map.get(String.valueOf(request.getPolicyHolder().getCardType())));
        holder.setIdNum(request.getPolicyHolder().getCardNo());
        holder.setMobile(request.getPolicyHolder().getMobile() == null ? "" : request.getPolicyHolder().getMobile());
        holder.setEmail(request.getPolicyHolder().getEmail() == null ? "" : request.getPolicyHolder().getEmail());
        datas.setHolder(holder);
        //被保人
        List<InsuredInfoDTO> infoDTOS = request.getInsureds();
        //被保人迭代器
        Iterator<InsuredInfoDTO> iterator = infoDTOS.iterator();
        //循环迭代 设置被保人信息
        int i = 0;
        while (iterator.hasNext()) {
            i++;
            InsuredInfoDTO next = iterator.next();
            Data.Insured insured = new Data.Insured();
            insured.setId(i);
            insured.setName(next.getCName());
            insured.setSex(BASE_WOMAN.equals(next.getSex()) ? "2" : "1");
            insured.setBirthday(next.getBirthDay());
            insured.setIdType(GeneraliEntity.map.get(String.valueOf(next.getCardType())));
            insured.setIdNum(next.getCardNo());
            // TODO
            insured.setRelaToInsured(01);
            insureds.add(insured);
        }
        datas.setInsureds(insureds);
        generaliEntity.setData(datas);
        //将数据转为json字符串格式
        String json = JSONObject.toJSONString(generaliEntity);
        //密钥
        String signStr = MD5Utils.MD5Lower(generaliEntity.getAgencyUserId() + privateKey + json);

        //发起询价请求
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> httpEntity = new HttpEntity(json, headers);
        ResponseEntity<String> quoteRes = restTemplate.postForEntity(submitUrl + QUOTE + "?sign=" + signStr, httpEntity, String.class);
        JSONObject quoteJson = JSONObject.parseObject(quoteRes.getBody());
        log.info("中意询价结果返回:{}", quoteJson);

        //TODO 询价请求结束
        if (RESPONSE_SUCCESS_CODE == quoteJson.getInteger(RETURN_CODE) && OK.equals(quoteJson.get(RETURN_MSG))) {
            //获取价格
            Double totalPremium = quoteJson.getJSONObject("data").getDouble("totalPremium");
            /***投保****/
            //TODO
            policyInfo.setNoType("");
            policyInfo.setNoCode("");
            policyInfo.setTravelToAddress(null == request.getOrder().getDestination() ? "" : request.getOrder().getDestination());
            policyInfo.setTravelFromAddress("");
            //TODO 询价返回价格
            policyInfo.setExpectedPremium(totalPremium);
            //TODO备注
            datas.setPolicyInfo(policyInfo);
            datas.setBeneficiaryList(beneficiaryList);
            generaliEntity.setData(datas);
            //重新转换json字符串 发送新的密钥
            json = JSONObject.toJSONString(generaliEntity);
            log.info("参数:{}", json);
            signStr = MD5Utils.MD5Lower(generaliEntity.getAgencyUserId() + privateKey + json);
            try {
                HttpEntity<String> submit = new HttpEntity(json, headers);
                ResponseEntity<String> submitRes = restTemplate.postForEntity(submitUrl + NSELL + "?sign=" + signStr, submit, String.class);
                JSONObject submitJson = JSONObject.parseObject(submitRes.getBody());
                log.info("投保返回:{}", submitJson);
                //保存返回结果
                OrderDetail orderDetail = baseOrderMapper.selectDeatailByOrderId(order.getId());
                orderDetail.setInsureRsp(JSONUtil.toJsonStr(submitJson));
                baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);

                if (RESPONSE_SUCCESS_CODE == submitJson.getInteger(RETURN_CODE) && OK.equals(submitJson.getString(RETURN_MSG))) {
                    log.info("投保成功!:{}", submitJson);
                    JSONObject data = submitJson.getJSONObject("data");
                    order.setStatus(OrderEnum.CLOSED_NO_REFUND.getValue());
                    order.setPolicyNo(data.getString("policyNum"));
                    baseOrderMapper.updateById(order);
                    return CommonInsureResult.submitPolicySuccess(data.getString("policyNum"));
                }
                log.info("投保失败,错误信息为:{}", submitJson.getString(RETURN_MSG));
                return CommonInsureResult.submitPolicyFail(submitJson.getString(RETURN_MSG));
            } catch (Exception e) {
                log.info("中意投保出现异常,异常信息为:{}", e.getMessage());
                return CommonInsureResult.submitPolicyFail();
            }
        }

        return CommonInsureResult.submitPolicyFail(quoteJson.getString(RETURN_MSG));
    }


    /**
     * @param request 退保信息
     */
    @Override
    public CommonInsureResult cancelPolicy(CancelInsureDTO request) {
        //密钥等信息
        String submitUrl = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
        String agencyUserId = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.AGENCY_USERID);
        String privateKey = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.PRIVATE_KEY);

        Order order = baseOrderMapper.selectByPolicyNoAndCompany(request.getPolicyNo(), CompanyEnum.GENERALI.getCode());
        GeneraliEntity generaliEntity = new GeneraliEntity();
        generaliEntity.setTransNo(order.getSerialNo());
        generaliEntity.setAgencyUserId(agencyUserId);
        generaliEntity.setCreateTime(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss"));
        //中意业务json字符串
        Data datas = new Data();
        datas.setPolicyNumber(request.getPolicyNo());

        generaliEntity.setData(datas);
        String json = JSONObject.toJSONString(generaliEntity);

        System.out.println("json字符串:" + json);
        //密钥
        String signStr = MD5Utils.MD5Lower(generaliEntity.getAgencyUserId() + privateKey + json);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> httpEntity = new HttpEntity(json, headers);
        ResponseEntity<String> quoteRes = restTemplate.postForEntity(submitUrl + CANCELLATION + "?sign=" + signStr, httpEntity, String.class);
        JSONObject jsonObject = JSONObject.parseObject(quoteRes.getBody());
        log.info("中意退保结果返回:{}", jsonObject);
        //保存返回结果
        OrderDetail orderDetail = baseOrderMapper.selectDeatailByOrderId(order.getId());
        orderDetail.setCancelPolicyRsp(JSONUtil.toJsonStr(jsonObject));
        baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);

        if (RESPONSE_SUCCESS_CODE == jsonObject.getInteger(RETURN_CODE) && OK.equals(jsonObject.getString(RETURN_MSG))) {
            order.setStatus(OrderEnum.CANCEL.getValue());
            baseOrderMapper.updateById(order);
            return CommonInsureResult.cancelPolicySuccess();
        }
        log.info("退保失败,错误信息为:{}", jsonObject.getString("returnMsg"));
        return CommonInsureResult.cancelPolicyFail(jsonObject.getString("returnMsg"));
    }

    @Override
    public CommonInsureResult downloadPolicy(DownloadInsureDTO downloadInsure) {
        //密钥等信息
        String submitUrl = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
        String agencyUserId = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.AGENCY_USERID);
        String privateKey = configService.getConfigValue(CompanyEnum.GENERALI, PolicyConfigKeyEnum.PRIVATE_KEY);
        //订单
        Order order = baseOrderMapper.selectByPolicyNoAndCompany(downloadInsure.getPolicyNo(), CompanyEnum.GENERALI.getCode());
        //转换java类型
        GeneraliEntity generaliEntity = new GeneraliEntity();
        generaliEntity.setTransNo(order.getSerialNo());
        generaliEntity.setAgencyUserId(agencyUserId);
        generaliEntity.setCreateTime(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss"));
        //中意业务json字符串
        Data datas = new Data();
        datas.setPolicyNumber(downloadInsure.getPolicyNo());
        generaliEntity.setData(datas);
        String json = JSONObject.toJSONString(generaliEntity);
        //密钥
        String signStr = MD5Utils.MD5Lower(generaliEntity.getAgencyUserId() + privateKey + json);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> httpEntity = new HttpEntity(json, headers);
        log.info("密钥:{}", signStr);
        log.info("json:{}", json);
        ResponseEntity<String> quoteRes = restTemplate.postForEntity(submitUrl + GENERATEDOC + "?sign=" + signStr, httpEntity, String.class);
        JSONObject jsonObject = JSONObject.parseObject(quoteRes.getBody());
        log.info("中意打印保单返回:{}", jsonObject);
        if (RESPONSE_SUCCESS_CODE == jsonObject.getInteger(RETURN_CODE) && OK.equals(jsonObject.getString(RETURN_MSG))) {
            byte[] bytes1 = new byte[0];
            try {
                bytes1 = new BASE64Decoder().decodeBuffer(jsonObject.getJSONObject("data").getString("policyPdf"));
            } catch (IOException e) {
                return CommonInsureResult.downloadPolicyFail("下载失败!");
            }
            return CommonInsureResult.downloadPolicySuccess(bytes1);
        }
        return CommonInsureResult.downloadPolicyFail();
    }

}
